package org.yanfengying.user.service.impl;

import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.yanfengying.constants.WxConstants;
import org.yanfengying.dto.AccountRegisterDTO;
import org.yanfengying.dto.BinderDTO;
import org.yanfengying.dto.NoticeContentDTO;
import org.yanfengying.user.domain.Logininfo;
import org.yanfengying.user.domain.User;
import org.yanfengying.user.domain.Wxuser;
import org.yanfengying.user.mapper.LogininfoMapper;
import org.yanfengying.user.mapper.UserMapper;
import org.yanfengying.user.mapper.WxuserMapper;
import org.yanfengying.user.service.IUserService;
import org.yanfengying.utils.AjaxResult;
import org.yanfengying.utils.HttpClientUtils;
import org.yanfengying.utils.MD5Utils;
import org.yanfengying.utils.config.RegisterNoticeRabbitmqConfig;
import org.yanfengying.utils.service.impl.BastServerImpl;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author yanfengying
 * @since 2022-11-14
 */
@Service
public class UserServiceImpl extends BastServerImpl<User> implements IUserService {

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private LogininfoMapper logininfoMapper;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private WxuserMapper wxuserMapper;
    @Autowired
    private UserMapper userMapper;

    @Override
    public void phoneRegister(AccountRegisterDTO dto) {
        //获取参数
        String confirmPassword = dto.getConfirmPassword();
        String mobile = dto.getMobile();
        String password = dto.getPassword();
        String smsCode = dto.getSmsCode();
        String username = dto.getUsername();

        //参数校验
        if(StringUtils.isEmpty(mobile)|| StringUtils.isEmpty(confirmPassword) || StringUtils.isEmpty(password)|| StringUtils.isEmpty(smsCode)|| StringUtils.isEmpty(username)){
            throw new RuntimeException("参数不能为空,请检查后重新输入");
        }

        //密码校验是否一致
        if(!password.equals(confirmPassword)){
            //不相等
            throw new RuntimeException("两次密码不相同,请检查后重新输入");
        }
        //校验手机验证码是否存在
        String smsCodeStr = (String)redisTemplate.opsForValue().get("regiser_sms_code_" + mobile);
        smsCodeStr = smsCodeStr.split(":")[0];

        if(StringUtils.isEmpty(smsCodeStr)){
            throw new RuntimeException("验证码已过期请重新获取!");
        }
        if(!smsCode.equals(smsCodeStr)){
            throw new RuntimeException("验证码错误,请重新输入!");
        }
        // 保存信息到logininfo表中
        Logininfo logininfo = new Logininfo();
        logininfo.setDisable(1);//是否启用
        logininfo.setPhone(mobile);
        logininfo.setType(1);//门户网站注册->用户状态
        logininfo.setUsername(username);
        //设置密码->加盐加密
        String salt = UUID.randomUUID().toString();
        logininfo.setSalt(salt);
        password = MD5Utils.encrypByMd5("123" + salt + "456" + password);
        logininfo.setPassword(password);
        logininfoMapper.insert(logininfo);

        //保存信息到user表中
        User user = new User();
        user.setPhone(mobile);
        user.setPassword(password);
        user.setSalt(salt);
        user.setState(1);
        user.setLogininfoId(logininfo.getId());
        user.setCreatetime(new Date());

        //注册成功以后发哦送信息通知用户
        rabbitTemplate.convertAndSend(RegisterNoticeRabbitmqConfig.EXCHANGE_TOPICS_INFORM,
                "inform.sms",
                new NoticeContentDTO(mobile,"您已经成功完成怨种公司的账号注册"));
        rabbitTemplate.convertAndSend(RegisterNoticeRabbitmqConfig.EXCHANGE_TOPICS_INFORM,
                "inform.email",
                new NoticeContentDTO(mobile,"您已经成功完成怨种公司的账号注册"));
    }

    @Override
    @Transactional
    public AjaxResult bindWxchat(BinderDTO dto) {
        //1 参数获取->非空校验
        String mobile = dto.getMobile();
        String accessToke = dto.getAccessToken();
        String openid = dto.getOpenid();
        String verifyCode = dto.getVerifyCode();
        if(StringUtils.isEmpty(mobile) || StringUtils.isEmpty(accessToke) || StringUtils.isEmpty(openid) || StringUtils.isEmpty(verifyCode)){
            throw new RuntimeException("参数错误!请重新输入");
        }
        //2 校验手机验证码
        String binderSmsCode = (String)redisTemplate.opsForValue().get("binder_sms_code_" + mobile);
        if(StringUtils.isEmpty(binderSmsCode)){//验证码过期
            throw new RuntimeException("验证码已过期,请重新获取");
        }
        binderSmsCode = binderSmsCode.split(":")[0];
        if(!binderSmsCode.equalsIgnoreCase(verifyCode)){//不相等(忽略大小写)
            throw new RuntimeException("验证码不相等,请重新输入");
        }
        //3 根据手机号查询user表是否已经存在该用户
        User user = userMapper.loaduUserByphone(mobile);
        Logininfo logininfo = null;

        //3.1存在->判断用户是否绑定微信用户
        if(Objects.nonNull(user)){//存在
            Wxuser wxuser = wxuserMapper.loadWxuserByUserId(user.getId());
            //判断是否绑定微信用户
            if(Objects.nonNull(wxuser)){//已经绑定用户->提醒用户先解绑
                return AjaxResult.me().setMessage("该手机号已绑定微信用户请解绑后在进行绑定操作")
                        .setSuccess(false);
            }else {
          //未绑定用户->将用户和微信进行绑定->并且免密登录(保存信息到wxuser/user/logininfo)
                //创建一个wx用户对象,将三方穿过来的信息存到wxuser表中
                Wxuser wxuser1 = builderWxuser(accessToke,openid);
                wxuser1.setUserId(user.getId());
                wxuserMapper.insert(wxuser1);
                //免密登录->获取logininfo表中的数据->传给前端存到localstage中
                logininfo = logininfoMapper.loadByUserId(user.getId());
            }
        }
        else {
        //3.2不存在->直接添加登录信息(logininfo/user/wxuser)
            //保存信息到logininfo表中
            logininfo = buildLogininfo(mobile);
            logininfo.setPhone(mobile);
            logininfoMapper.insert(logininfo);
            //封装user对象
            user = logininfo2User(logininfo);
            userMapper.insert(user);
            //封装wxUser对象
            Wxuser wxuser = builderWxuser(accessToke, openid);
            wxuser.setUserId(user.getId());
            wxuserMapper.insert(wxuser);
        }
        //4 免密登录->创建一个token->将信息传给前端
        String token = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set(token,logininfo,30, TimeUnit.MINUTES);
        HashMap<String, Object> map = new HashMap<>();
        map.put("token", token);
        //将密码和盐值重新设置保证安全性
        logininfo.setPassword("");
        logininfo.setSalt("");
        map.put("loginInfo", logininfo);
        return AjaxResult.me().setResult(map);
    }

    private User logininfo2User(Logininfo logininfo) {
        User user = new User();
        BeanUtils.copyProperties(logininfo, user);
        user.setCreatetime(new Date());
        user.setLogininfoId(logininfo.getId());
        user.setState(2);
        return user;
    }

    private Logininfo buildLogininfo(String mobile) {
        Logininfo logininfo = new Logininfo();
        //设置默认的用户名/密码/状态
        logininfo.setType(1);
        logininfo.setUsername(UUID.randomUUID().toString());
        String salt = UUID.randomUUID().toString();
        logininfo.setSalt(salt);
        String password = MD5Utils.encrypByMd5("123" + salt + "456" + "123456");
        logininfo.setPassword(password);
        logininfo.setDisable(1);
        return logininfo;
    }

    private Wxuser builderWxuser(String accessToke, String openid) {
        //通过三方拿到信息
        String wxStrUrl = WxConstants.GET_USER_URL.replace("ACCESS_TOKEN", accessToke)
                .replace("OPENID", openid);
        String wxStr = HttpClientUtils.httpGet(wxStrUrl);
        //将字符串转化为对象
        JSONObject jsonObject = JSONObject.parseObject(wxStr);
        if(jsonObject.getString("openid") == null){
            throw new RuntimeException("授权登录信息已过期,请重新扫码");
        }
        //设置相关信息
        Wxuser wxuser = new Wxuser();
        wxuser.setOpenid(jsonObject.getString("openid"));
        wxuser.setNickname(jsonObject.getString("nickname"));
        wxuser.setSex(jsonObject.getInteger("sex"));
        wxuser.setUnionid(jsonObject.getString("unionid"));
        wxuser.setHeadimgurl(jsonObject.getString("headimgurl"));
        String country = jsonObject.getString("country");
        String province = jsonObject.getString("province");
        String city = jsonObject.getString("city");
        wxuser.setAddress(country+province+city);
        return wxuser;
    }
}
